﻿using Digitalmes.Application.Configuration;

namespace Digitalmes.Application.Mes;

[ApiExplorerSettings(GroupName = "mes")]
public sealed class ProdTransSnService : IDynamicWebApiService
{
    private readonly SugarRepository<ProdTransSn> _transSnRepo;
    private readonly SugarRepository<ProdTransSnRecord> _transSnRecordRepo;
    private readonly SugarRepository<ProdWo> _woRepo;
    private readonly ProcessQueryService _processQueryService;

    private readonly ApplicationConfig _appConfig;

    public ProdTransSnService(SugarRepository<ProdTransSn> transSnRepo,
        SugarRepository<ProdTransSnRecord> transSnRecordRepo, 
        SugarRepository<ProdWo> woRepo,
        ProcessQueryService processQueryService,
        IOptions<ApplicationConfig> appConfigOptions)
    {
        _transSnRepo = transSnRepo;
        _transSnRecordRepo = transSnRecordRepo;
        _woRepo = woRepo;
        _processQueryService = processQueryService;

        _appConfig = appConfigOptions.Value;
    }

    /// <summary>
    /// 查询所有——分页
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<PageResult<ProdTransSnDto>> GetPagesAsync(ProdTransSnPageParam param)
    {
        var query = await _transSnRepo.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(param.Sn), s => s.Sn == param.Sn)
            .WhereIF(!string.IsNullOrEmpty(param.CustomerSn), s => s.CustomerSn == param.CustomerSn)
            .WhereIF(param.StartTime != null, a => a.OutboundTime >= param.StartTime.MinTime())
            .WhereIF(param.EndTime != null, a => a.OutboundTime <= param.EndTime.MaxTime())
            .OrderByDescending(s => s.Id)
            .ToPageAsync(param.Page, param.Limit);
        return query.Adapt<PageResult<ProdTransSnDto>>();
    }

    /// <summary>
    /// 模糊查询所有——分页
    /// </summary>
    /// <param name="param"></param>
    /// <returns></returns>
    [HttpGet]
    public async Task<PageResult<ProdTransSnDto>> GetPagesLikeAsync(ProdTransSnPageParam param)
    {
        var query = await _transSnRepo.AsQueryable()
            .WhereIF(!string.IsNullOrEmpty(param.Sn), s => s.Sn.Contains(param.Sn!))
            .OrderByDescending(s => s.Id)
            .ToPageAsync(param.Page, param.Limit);
        return query.Adapt<PageResult<ProdTransSnDto>>();
    }

    /// <summary>
    /// 根据主键查询
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    [HttpGet("{id}")]
    public async Task<ProdTransSnDto> GetAsync(long id)
    {
        var model = await _transSnRepo.GetByIdAsync(id);
        return model.Adapt<ProdTransSnDto>();
    }

    /// <summary>
    /// 让步接收
    /// </summary>
    /// <returns></returns>
    [UnitOfWork]
    [HttpPost]
    public async Task<BooleanResult> ConcessionAsync(ProdTransSnParam param)
    {
        // 前置条件：
        //  1、产品没有开返工单
        // 动作：
        //  1、将产品的状态更改为 "OK"；
        //  2、将产品在该工位的最近一次过站记录更改为 "OK
        //  3、若有工单，不合格数量-1；
        //  4、若是尾序，增加 合格数量和完工数量，同时更改工单状态（自动工单）

        var transSn = await _transSnRepo.GetByIdAsync(param.Id);
        if (transSn == null)
        {
            return BooleanResult.Error("没有找到对应的数据");
        }

        // 仅 NG 才能进行让步接收
        if (transSn.Status != SnStatusEnum.NG)
        {
            return BooleanResult.Error("仅产品状态 NG 才能进行让步接收");
        }
        // 不能已开返工单
        if (transSn.ReworkFlag != ReworkFlagEnum.None)
        {
            return BooleanResult.Error("SN 已开返工单，不能让步接收");
        }

        transSn.Status = SnStatusEnum.OK;

        // 检查是否为尾序
        bool isFinnal = await _processQueryService.IsFinalAsync(transSn.CurRoutingCode, transSn.CurOpCode); 
        if (isFinnal)
        {
            transSn.IsCompelted = true;
            transSn.OfflineTime = DateTime.Now;
        }

        await _transSnRepo.UpdateAsync(transSn, m => new { m.Status, m.IsCompelted, m.OfflineTime });

        // 更改过站状态
        var transSnRecord = await _transSnRecordRepo.GetLastAsync(s => s.Sn ==  transSn.Sn && s.OpId == transSn.CurOpId);
        if (transSnRecord != null)
        {
            transSnRecord.PassResult = PassResultEnum.MandatoryOK;
            await _transSnRecordRepo.UpdateAsync(transSnRecord, m => new { m.PassResult });
        }

        if (!string.IsNullOrEmpty(transSn.Wo))
        {
            var workOrder = await _woRepo.GetFirstAsync(s => s.Wo == transSn.Wo);
            workOrder.UnqualifiedQty -= 1;

            // 尾站
            if (isFinnal)
            {
                workOrder.QualifiedQty += 1;
                workOrder.CompletedQty += 1;

                // 若是设置为自动完工
                if (_appConfig.WorkOrder.IsAutoCompleteAndSwitch)
                {
                    if (workOrder.CompletedQty == workOrder.TotalQty)
                    {
                        workOrder.SetStatus(WoStatusEnum.Completed);
                        workOrder.ActualEndTime = DateTime.Now;
                    }
                }
            }

            await _woRepo.UpdateAsync(workOrder, s => new
            {
                s.ActualEndTime,
                s.Status,
                s.LastStatus,
                s.CompletedQty,
                s.QualifiedQty,
                s.UnqualifiedQty,
                s.UpdateTime,
            });
        }

        return BooleanResult.Ok();
    }

    /// <summary>
    /// 强制 NG
    /// </summary>
    /// <returns></returns>
    [UnitOfWork]
    [HttpPost]
    public async Task<BooleanResult> MandatoryNGAsync(ProdTransSnParam param)
    {
        // 动作：
        //  1、将产品的状态更改为 "NG"；
        //  2、若有工单，不合格数量+1;
        //  3、若是尾序，减少 合格数量和完工数量，同时回滚工单状态（自动工单）

        var transSn = await _transSnRepo.GetByIdAsync(param.Id);
        if (transSn == null)
        {
            return BooleanResult.Error("没有找到对应的数据");
        }

        // 仅 OK 才能进行强制 NG
        if (transSn.Status != SnStatusEnum.OK)
        {
            return BooleanResult.Error("仅产品状态 OK 才能进行强制 NG");
        }

        transSn.Status = SnStatusEnum.NG;
        await _transSnRepo.UpdateAsync(transSn, m => new { m.Status });

        // 更改过站状态
        var transSnRecord = await _transSnRecordRepo.GetLastAsync(s => s.Sn == transSn.Sn && s.OpId == transSn.CurOpId);
        if (transSnRecord != null)
        {
            transSnRecord.PassResult = PassResultEnum.MandatoryNG;
            await _transSnRecordRepo.UpdateAsync(transSnRecord, m => new { m.PassResult });
        }

        if (!string.IsNullOrEmpty(transSn.Wo))
        {
            var workOrder = await _woRepo.GetFirstAsync(s => s.Wo == transSn.Wo);
            workOrder.UnqualifiedQty += 1;

            // 检查是否为尾序
            bool isFinnal = await _processQueryService.IsFinalAsync(transSn.CurRoutingCode, transSn.CurOpCode);
            if (isFinnal)
            {
                workOrder.QualifiedQty -= 1;
                workOrder.CompletedQty -= 1;

                // 将工单状态回滚
                if (_appConfig.WorkOrder.IsAutoCompleteAndSwitch)
                {
                    if (workOrder.CompletedQty < workOrder.TotalQty && workOrder.Status == WoStatusEnum.Completed)
                    {
                        workOrder.SetStatus(WoStatusEnum.Executing);
                        workOrder.ActualEndTime = DateTime.Now;
                    }
                }
            }

            await _woRepo.UpdateAsync(workOrder, s => new
            {
                s.ActualEndTime,
                s.Status,
                s.LastStatus,
                s.CompletedQty,
                s.QualifiedQty,
                s.UnqualifiedQty,
                s.UpdateTime,
            });
        }

        return BooleanResult.Ok();
    }

    /// <summary>
    /// 报废
    /// </summary>
    /// <returns></returns>
    [UnitOfWork]
    [HttpPost]
    public async Task<BooleanResult> ScrapAsync(ProdTransSnParam param)
    {
        // 动作：
        //  1、将产品的状态更改为 "Scrap"；
        //  2、若有工单，报废数量+1;
        //  3、若是尾序，增加 完工数量，同时更改工单状态（自动工单）

        var transSn = await _transSnRepo.GetByIdAsync(param.Id);
        if (transSn == null)
        {
            return BooleanResult.Error("没有找到对应的数据");
        }

        // 仅 NG 才能进行报废
        if (transSn.Status != SnStatusEnum.NG)
        {
            return BooleanResult.Error("仅产品状态 NG 才能进行报废");
        }

        transSn.Status = SnStatusEnum.Scrap;
        await _transSnRepo.UpdateAsync(transSn, m => new { m.Status });

        if (!string.IsNullOrEmpty(transSn.Wo))
        {
            var workOrder = await _woRepo.GetFirstAsync(s => s.Wo == transSn.Wo);
            workOrder.ScrapQty += 1;

            // 检查是否为尾序
            bool isFinnal = await _processQueryService.IsFinalAsync(transSn.CurRoutingCode, transSn.CurOpCode);
            if (isFinnal)
            {
                workOrder.CompletedQty += 1;

                // 若是设置为自动完工
                if (_appConfig.WorkOrder.IsAutoCompleteAndSwitch)
                {
                    if (workOrder.CompletedQty == workOrder.TotalQty)
                    {
                        workOrder.SetStatus(WoStatusEnum.Completed);
                        workOrder.ActualEndTime = DateTime.Now;
                    }
                }
            }

            await _woRepo.UpdateAsync(workOrder, s => new
            {
                s.ActualEndTime,
                s.Status,
                s.LastStatus,
                s.CompletedQty,
                s.QualifiedQty,
                s.ScrapQty,
                s.UpdateTime,
            });
        }

        return BooleanResult.Ok();
    }
}
